#include <time.h>
#include <stdlib.h>
#include "tyan.h"
#include "tyn_searchd.h"

term32_index_t *g_term_index = NULL;

int main(int argc, char **argv) {
    config_t cfg;
    config_init(&cfg);

    char *config_file_name = "tyan.conf";
    tyn_config_t *tyn_config = load_config(config_file_name, &cfg);
    if(tyn_config == TYN_ERROR) {
        tyn_log(stderr, "Failed parsing %s", config_file_name);
        return TYN_ERROR;
    }
    
    char *index_name = "mysql_index";
    int fd_tyi;
    int fd_tyd;
    int fd_tyf;
    int fd_typ;
    for(int i = 0; i < tyn_config->indexes_count; i++) {
        tyn_config_index_t *tyn_config_index = *(tyn_config->indexes + i);
        if(index_name) {
            if(strcmp(tyn_config_index->index_name, index_name) != 0) {
                continue;
            }
        }
        //load tyi
        char fname_tyi[256];
        sprintf(fname_tyi, "%s.tyi", tyn_config_index->index_name);
        fd_tyi = open(fname_tyi, O_RDWR);
        
        char fname_tyd[256];
        sprintf(fname_tyd, "%s.tyd", tyn_config_index->index_name);
        fd_tyd = open(fname_tyd, O_RDWR);
        
        char fname_tyf[256];
        sprintf(fname_tyf, "%s.tyf", tyn_config_index->index_name);
        fd_tyf = open(fname_tyf, O_RDWR);
        
        char fname_typ[256];
        sprintf(fname_typ, "%s.typ", tyn_config_index->index_name);
        fd_typ = open(fname_typ, O_RDWR);
        
        size_t buffer_size = 1024*1024;
        char *buffer = (char *)malloc( buffer_size );
        char *buffer_ptr;
        
        size_t total_bytes = 0;
        size_t total_num = 0;
        //while(1) {
            uint32_t str_len;
            uint8_t encoded_size;
            
            int bytes_read = 0;
            size_t bytes_left = bytes_read;
            off_t offset_doc = 0;
            off_t offset_freq = 0;
            off_t offset_pos = 0;
            while(1) {
                if(bytes_left < sizeof(uint32_t)) {
                    lseek(fd_tyi, 0 - bytes_left, SEEK_CUR);
                    bytes_left = bytes_read = tyn_read(fd_tyi, buffer, buffer_size);
                    buffer_ptr = buffer;
                    if(bytes_read == 0) {
                        printf("end of file1\n");
                        break;
                    }
                }
                memcpy(&str_len, buffer_ptr, sizeof(uint32_t));
                term32_index_t *term_index_entry = (term32_index_t *)malloc( sizeof(term32_index_t) );
                term_index_entry->str_len = str_len;
                buffer_ptr += sizeof(uint32_t);
                bytes_left -= sizeof(uint32_t);

                if(bytes_left < str_len) {
                    lseek(fd_tyi, 0 - bytes_left, SEEK_CUR);
                    bytes_left = bytes_read = tyn_read(fd_tyi, buffer, buffer_size);
                    buffer_ptr = buffer;
                    if(bytes_read == 0) {
                        printf("end of file2\n");
                        break;
                    }
                }
                //fwrite(buffer_ptr, 1, str_len, stdout);
                //printf("\n");
                term_index_entry->str = (char *)malloc( term_index_entry->str_len );
                memcpy(term_index_entry->str, buffer_ptr, str_len);
                buffer_ptr += str_len;
                bytes_left -= str_len;
                
                if(bytes_left < sizeof(uint8_t)) {
                    lseek(fd_tyi, 0 - bytes_left, SEEK_CUR);
                    bytes_left = bytes_read = tyn_read(fd_tyi, buffer, buffer_size);
                    buffer_ptr = buffer;
                    if(bytes_read == 0) {
                        printf("end of file3\n");
                        break;
                    }
                }
                memcpy(&encoded_size, buffer_ptr, sizeof(uint8_t));
                buffer_ptr += sizeof(uint8_t);
                bytes_left -= sizeof(uint8_t);
                
                
                if(bytes_left < encoded_size) {
                    lseek(fd_tyi, 0 - bytes_left, SEEK_CUR);
                    bytes_left = bytes_read = tyn_read(fd_tyi, buffer, buffer_size);
                    buffer_ptr = buffer;
                    if(bytes_read == 0) {
                        printf("end of file4\n");
                        break;
                    }
                }
                term32_index_entry_t index;
                int num_decoded = tyn_iS16_decode32(buffer_ptr, &index, &encoded_size);
                if(num_decoded != sizeof(term32_index_entry_t) / sizeof(uint32_t)) {
                    printf("decoding error detected\n");
                }
                term_index_entry->num_encoded_doc = index.num_encoded_doc;
                term_index_entry->num_encoded_freq = index.num_encoded_freq;
                term_index_entry->num_encoded_pos = index.num_encoded_pos;
                
                term_index_entry->size_encoded_doc = index.size_encoded_doc;
                term_index_entry->size_encoded_freq = index.size_encoded_freq;
                term_index_entry->size_encoded_pos = index.size_encoded_pos;

                term_index_entry->offset_doc = offset_doc;
                term_index_entry->offset_freq = offset_freq;
                term_index_entry->offset_pos = offset_pos;
                
                offset_doc += index.size_encoded_doc;
                offset_freq += index.size_encoded_freq;
                offset_pos += index.size_encoded_pos;
                
                buffer_ptr += encoded_size;
                bytes_left -= encoded_size;
            
                //-----------------------------------------------
                //add new term index
                total_num++;
                total_bytes += sizeof(uint32_t) + str_len + sizeof(uint8_t) + encoded_size;
                HASH_ADD_KEYPTR( hh, g_term_index, term_index_entry->str, term_index_entry->str_len, term_index_entry );
            }
            total_bytes += bytes_read;

        //-------------------------------------------------------------------------------------------
        //verifying index
        size_t size_check_doc = 0;
        size_t size_check_freq = 0;
        size_t size_check_pos = 0;
        printf("verifying index\n");
        size_t buffer_encode_size = 1024000;
        size_t buffer_decode_size = 1024000;
        char *buffer_encoding = (char *)malloc(buffer_encode_size);
        char *buffer_decoding = (char *)malloc(buffer_decode_size);
        term32_index_t *s, *tmp;
        HASH_ITER(hh, g_term_index, s, tmp) {
            //printf("user id %d: str %s\n", s->id, s->str);
            //printf("%s:%u, offset_doc:%u, freq:%u, pos:%u, size_encoded_doc:%u, freq:%u, pos:%u, num_doc:%u, num_freq:%u, num_pos:%u\n", s->str, s->id, s->offset_doc, s->offset_freq, 
            //       s->offset_pos, s->size_encoded_doc, s->size_encoded_freq, s->size_encoded_pos, s->num_encoded_doc, s->num_encoded_freq, s->num_encoded_pos );
            size_check_doc += s->size_encoded_doc;
            size_check_freq += s->size_encoded_freq;
            size_check_pos += s->size_encoded_pos;
            
            int bytes_read;
            size_t num_decoded;
            //---------------------------------------------------------------------------------------
            //printf("verifying doc\n");
            if(buffer_encode_size < s->size_encoded_doc) {
                free(buffer_encoding);
                buffer_encoding = (char *)malloc( s->size_encoded_doc );
            }
            if(buffer_decode_size < s->num_encoded_doc * sizeof(uint32_t)) {
                free(buffer_decoding);
                buffer_decoding = (char *)malloc( s->num_encoded_doc* sizeof(uint32_t) );
            }
            
            pread(fd_tyd, buffer_encoding, s->size_encoded_doc, s->offset_doc);
            num_decoded = tyn_p4d_decode32(buffer_encoding, buffer_decoding, &bytes_read);
            if(num_decoded != s->num_encoded_doc || bytes_read != s->size_encoded_doc) {
                printf("decode doc error\n");
            }
            //---------------------------------------------------------------------------------------
            //printf("verifying freq\n");
            if(buffer_encode_size < s->size_encoded_freq) {
                free(buffer_encoding);
                buffer_encoding = (char *)malloc( s->size_encoded_freq );
            }
            if(buffer_decode_size < s->num_encoded_freq * sizeof(uint32_t)) {
                free(buffer_decoding);
                buffer_decoding = (char *)malloc( s->num_encoded_freq* sizeof(uint32_t) );
            }
            
            pread(fd_tyf, buffer_encoding, s->size_encoded_freq, s->offset_freq);
            bytes_read;
            num_decoded = tyn_p4d_decode32(buffer_encoding, buffer_decoding, &bytes_read);
            if(num_decoded != s->num_encoded_freq || bytes_read != s->size_encoded_freq) {
                printf("decode freq error\n");
            }
            //---------------------------------------------------------------------------------------
            //printf("verifying pos\n");
            if(buffer_encode_size < s->size_encoded_pos) {
                free(buffer_encoding);
                buffer_encoding = (char *)malloc( s->size_encoded_pos );
            }
            if(buffer_decode_size < s->num_encoded_pos * sizeof(uint32_t)) {
                free(buffer_decoding);
                buffer_decoding = (char *)malloc( s->num_encoded_pos * sizeof(uint32_t) );
            }
            
            pread(fd_typ, buffer_encoding, s->size_encoded_pos, s->offset_pos);
            bytes_read;
            num_decoded = tyn_p4d_decode32(buffer_encoding, buffer_decoding, &bytes_read);
            if(num_decoded != s->num_encoded_pos || bytes_read != s->size_encoded_pos) {
                printf("decode pos error\n");
            }

            
        }
        free(buffer_encoding);
        free(buffer_decoding);

        printf("doc size should be:%u\n", size_check_doc);
        printf("freq size should be:%u\n", size_check_freq);
        printf("pos size should be:%u\n", size_check_pos);
        //-----------------------------------------------------------------------------------

            
            //}
        printf("total num:%d\n", total_num);
        printf("total bytes:%d\n", total_bytes);
        clock_t cl;
        cl = clock();
    }
    while(1) {
        
    }
    
    char *keyword = "的";
    term32_index_t *term_index_found;
    HASH_FIND(hh,g_term_index,keyword,strlen(keyword),term_index_found);
    if(term_index_found) {
        printf("%s\n", keyword);
        printf("\ttotal document: %d\n", term_index_found->num_encoded_doc);
        char *buffer_encoded_doc = (char *)malloc( term_index_found->size_encoded_doc );
        char *buffer_doc = (char *)malloc( term_index_found->num_encoded_doc * sizeof(uint32_t) );
        pread(fd_tyd, buffer_encoded_doc, term_index_found->size_encoded_doc, term_index_found->offset_doc);
        size_t bytes_read;
        size_t num_decoded = tyn_p4d_decode32(buffer_encoded_doc, buffer_doc, &bytes_read);
        if(num_decoded != term_index_found->num_encoded_doc || bytes_read != term_index_found->size_encoded_doc) {
            printf("decode doc error\n");
        }
        uint32_t *doc_id_ptr = buffer_doc;
        uint32_t last_doc_id = 0;
        for(int i = 0; i <  term_index_found->num_encoded_doc; i++) {
            uint32_t doc_id = last_doc_id + *doc_id_ptr;
            printf("doc id: %d\n", doc_id);
            last_doc_id = doc_id;
            doc_id_ptr++;
        }
    }
    //tyn_build_index(tyn_config, "mysql_index");
    
    config_destroy(&cfg);
    
}